﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace SimpleReminder
{
    public class EventMonthly : EventBase
    {
        public EventMonthly(DataRow dr)
            : base(dr)
        {
            if (base.Type != MyEvents.EventTypes.Monthly)
                throw new MyEvents.InvalidEventTypeException();
        }

        int _monthlyType;
        bool[] _monthly = new bool[12];
        int _monthlyDay;
        string _monthlyWeekNo;
        string _monthlyWeekDay;

        public override void From(DataRow dr)
        {
            base.From(dr);

            _monthlyType = ((bool)dr[MyEvents.COL_MONTHLY_TYPE1]) ? 1 : 2;
            _monthlyDay = (int)dr[MyEvents.COL_MONTHLY_DAY];
            _monthlyWeekNo = dr[MyEvents.COL_MONTHLY_WEEKNO] as string;
            _monthlyWeekDay = dr[MyEvents.COL_MONTHLY_WEEKDAY] as string;

            _monthly[0] = (bool)dr[MyEvents.COL_MONTHLY_JAN];
            _monthly[1] = (bool)dr[MyEvents.COL_MONTHLY_FEB];
            _monthly[2] = (bool)dr[MyEvents.COL_MONTHLY_MAR];
            _monthly[3] = (bool)dr[MyEvents.COL_MONTHLY_APR];
            _monthly[4] = (bool)dr[MyEvents.COL_MONTHLY_MAY];
            _monthly[5] = (bool)dr[MyEvents.COL_MONTHLY_JUN];
            _monthly[6] = (bool)dr[MyEvents.COL_MONTHLY_JUL];
            _monthly[7] = (bool)dr[MyEvents.COL_MONTHLY_AUG];
            _monthly[8] = (bool)dr[MyEvents.COL_MONTHLY_SEP];
            _monthly[9] = (bool)dr[MyEvents.COL_MONTHLY_OCT];
            _monthly[10] = (bool)dr[MyEvents.COL_MONTHLY_NOV];
            _monthly[11] = (bool)dr[MyEvents.COL_MONTHLY_DEC];
        }

        public override bool IsTimeToRun()
        {
            DateTime now = DateTime.Now;

            if (base.CanRun &&
                _monthly[now.Month - 1] &&
                StartDate.Hour == now.Hour &&
                StartDate.Minute == now.Minute &&
                (now - base.LastRunTime).TotalDays >= 1
                )
            {
                if (_monthlyType == 1)
                {
                    if (_monthlyDay == now.Day)
                    {
                        return true;
                    }
                }
                else if(_monthlyType == 2)
                {
                    if (now.Day == GetMonthDayForType2())
                    {
                        return true;       
                    }
                }
            }

            return false;
        }

        private int GetMonthDayForType2()
        {
            DateTime now = DateTime.Now;
            DateTime day1 = new DateTime(now.Year, now.Month, 1);
            int weekDay1 = (int) day1.DayOfWeek;
            int weekDay = GetWeekDay();
            int monthDay = 0;

            switch (_monthlyWeekNo)
            {
                case MyEvents.MONTHLY_WEEK_FIRST:
                    if (weekDay >= weekDay1) 
                        monthDay = day1.AddDays(weekDay - weekDay1).Day;
                    else 
                        monthDay = day1.AddDays(7 - weekDay1 + weekDay).Day;
                    break;
                case MyEvents.MONTHLY_WEEK_SECOND:
                    if (weekDay >= weekDay1)
                        monthDay = day1.AddDays(7 + weekDay - weekDay1).Day;
                    else
                        monthDay = day1.AddDays(14 - weekDay1 + weekDay).Day;
                    break;
                case MyEvents.MONTHLY_WEEK_THIRD:
                    if (weekDay >= weekDay1)
                        monthDay = day1.AddDays(14 + weekDay - weekDay1).Day;
                    else
                        monthDay = day1.AddDays(21 - weekDay1 + weekDay).Day;
                    break;
                case MyEvents.MONTHLY_WEEK_FOURTH:
                    if (weekDay >= weekDay1)
                        monthDay = day1.AddDays(21 + weekDay - weekDay1).Day;
                    else
                        monthDay = day1.AddDays(28 - weekDay1 + weekDay).Day;
                    break;
                case MyEvents.MONTHLY_WEEK_LAST:
                    DateTime dayLast = day1.AddMonths(1).AddDays(-1);
                    int weekDayLast = (int)dayLast.DayOfWeek;
                    if (weekDayLast >= weekDay) 
                        monthDay = monthDay = dayLast.AddDays(weekDay - weekDayLast).Day;
                    else 
                        monthDay = dayLast.AddDays(weekDay - weekDayLast - 7).Day;
                    break;
            }
            return monthDay;
        }
        
        private int GetWeekDay()
        {
            int day = 0;
            switch (_monthlyWeekDay)
            {
                case MyEvents.SUNDAY:
                    day = 0;
                    break;
                case MyEvents.MONDAY:
                    day = 1;
                    break;
                case MyEvents.TUESDAY:
                    day = 2;
                    break;
                case MyEvents.WEDNESDAY:
                    day = 3;
                    break;
                case MyEvents.THURSDAY:
                    day = 4;
                    break;
                case MyEvents.FRIDAY:
                    day = 5;
                    break;
                case MyEvents.SATURDAY:
                    day = 6;
                    break;
            }
            return day;
        }
    }
}
